package com.runa.monitor.platinterface.netservice.equipment;

import com.runa.monitor.comm.dto.Archive;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.dto.newComm.HotMeterVO;
import com.runa.monitor.comm.entity.CommMeter;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.backwork.impl.ApportionFunction;
import com.runa.monitor.platinterface.backwork.impl.RccTaskFunction;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.monitor.platinterface.netservice.equipment.dtu.DtuTaskFunction;
import com.runa.monitor.platinterface.netservice.equipment.dtu.point.ModbusPoints;
import com.runa.monitor.platinterface.netservice.equipment.dtu.point.TestPoints;
import com.runa.monitor.platinterface.task.RequestTask;
import com.runa.persistence.RepositoryServicePersis;
import com.runa.persistence.entity.apportion.ApportionValveControlParam;
import com.runa.protocol.dto.ModbusPoint;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.ConcentratorResponseData;
import com.runa.rccprotocol.dto.apportionCollector.ApportionCollectorRequestData;
import com.runa.rccprotocol.dto.equdata.EquData;
import com.runa.rccprotocol.dto.param.ExtendParam;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import com.runa.rccprotocol.em.ApportionCollectorModbusTypeEnum;
import com.runa.rccprotocol.netservice.modbus.ModbusRequest;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Slf4j
public class ApportionCollectorDriver extends NetEqu<String> {


    public ApportionCollectorDriver(String serial, Integer timeout) {
        super(serial, timeout);
    }

    @Override
    public void readNodeEqu(List<Node> nodeList, TaskFunction function, EquData.EquDataType type) {
        if (!online()) {
            function.doApply(CommStatus.OffLine, nodeList);
            return;
        }
        switch (type) {
            case METER:
                readHouseMeter(nodeList, function);
                break;
            case VALVE:
                readValve(nodeList, function);
                break;
            default:
        }
    }


    //runa 188
    private void readHouseMeter(List<Node> meters, TaskFunction function) {
        for (Node node : meters) {
            ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
            if ("PG".equals(node.getModel())) {
                requestData.readHeatMeterPG(Integer.parseInt(node.getSerial()));
            } else {
                requestData.readHeatMeter(node.getSerial());
            }
            log.debug("正定读取表: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
            requestData.setRemain(Collections.singletonList(node));
            sendRequest(requestData, function);
        }
    }

    private void readValve(List<Node> valveSerial, TaskFunction function) {
        for (Node node : valveSerial) {
            ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
            requestData.readValve(node.getSerial());
            log.debug("正定读取阀: {} {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
            requestData.setRemain(Collections.singletonList(node));
            sendRequest(requestData, function);
        }
    }

    private DtuTaskFunction dtuTaskFunction;

    private ModbusPoints points = new TestPoints(60);

    private void readDtuRequest(Node node, TaskFunction function) {
        dtuTaskFunction = new DtuTaskFunction(function, node, 1);
        List<ModbusPoint> modbusPointList = points.getModbusPointList();
        ModbusRequest modbusRequest = new ModbusRequest(serial());
        modbusRequest.setModbusPoints(modbusPointList);
        byte functionCode = ApportionCollectorModbusTypeEnum.functionCode(node.getModel());
        modbusRequest.readZdModbusData(node.getIndex(), Integer.valueOf(functionCode));
        log.info("正定MODBUS读取: {} {}", serial(), ByteUtil.byteToHexString(modbusRequest.getData()));
        dtuTaskFunction.addRequest(modbusRequest);
        sendRequest(modbusRequest, dtuTaskFunction);

    }

    public static void main(String[] args) {
        ApportionCollectorRequestData requestData = new ApportionCollectorRequestData("100011001");
//        requestData.readValve("21000010241088");
        requestData.setDebuggingModeSetTheTemperature("21000010241088", 22F);
        String s = ByteUtil.byteToHexString(requestData.getData());
        System.out.println(s);
    }

    @Override
    public void setNodeEquArchive(List<Archive> archives, TaskFunction function) {

    }

    @Override
    public void clearNodeEquArchive(TaskFunction function) {

    }

    public ApportionCollectorRequestData getRequest(Node node, int ctrl) {
        ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
        requestData.valveCtrl(node.getSerial(), ctrl);
        requestData.setRemain(node);
        return requestData;
    }

    public ApportionCollectorRequestData getValveOpenRequest(Node node, int open) {
        ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
        requestData.valveOnOffControl(node.getSerial(), open);
        requestData.setRemain(node);
        return requestData;
    }

    public void valveOnOffControl(ApportionValveControlParam valveControl, TaskFunction function) {
        Integer v = Integer.valueOf(valveControl.getValue());
        switch (valveControl.getType()) {
            case "锁定": // value 0:false 1:true
                if (v == 0) {
                    sendRequest(getRequest(valveControl.getNode(), 0xFF), function);
                } else if (v == 1) {
                    sendRequest(getRequest(valveControl.getNode(), 0x11), function);
                }
                break;
            case "强制开关": // value 0关，1开
                if (v == 0) {
                    sendRequest(getRequest(valveControl.getNode(), 0x99), function);
                } else if (v == 1) {
                    sendRequest(getRequest(valveControl.getNode(), 0x55), function);
                }
                break;
            case "开度":
                RequestTask task1 = new RequestTask(getRequest(valveControl.getNode(), 0xFF), new ApportionFunction(this, function.getPriority(), "自由模式"));
                RequestTask task2 = new RequestTask(getRequest(valveControl.getNode(), 0x11), new ApportionFunction(this, function.getPriority(), "锁定开度"));
                RequestTask task3 = new RequestTask(getValveOpenRequest(valveControl.getNode(), Integer.valueOf(valveControl.getValue())), function);
                task1.setNext(task2);
                task2.setNext(task3);
                sendRequest(task1);
                break;
            case "室温":
                valveTemperatureControl(valveControl.getNode(), (byte)0x55, valveControl.getValue(), valveControl.getTolerance(), valveControl.getTime(), function);
                break;
            case "回温":
                valveTemperatureControl(valveControl.getNode(), (byte)0x77, valveControl.getValue(), valveControl.getTolerance(), valveControl.getTime(), function);
                break;
            case "均温":
                valveTemperatureControl(valveControl.getNode(), (byte)0x66, valveControl.getValue(), valveControl.getTolerance(), valveControl.getTime(), function);
                break;
        }
    }


    public void valveTemperatureControl(Node node, byte mode, String value, String tolerance, String time, TaskFunction function) {
        RequestTask task1 = new RequestTask(getRequest(node, 0xFF), new ApportionFunction(this, function.getPriority(), "自由模式"));
        RequestTask task2 = new RequestTask(getRequest(node, 0x88), new ApportionFunction(this, function.getPriority(), "调试模式"));
        RequestTask task3 = new RequestTask(getRequest(node, mode), new ApportionFunction(this, function.getPriority(), "温控方式"));

        ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
        requestData.setTempOnDebug(node.getSerial(), Integer.valueOf(value), Integer.valueOf(tolerance), Integer.valueOf(time));
        requestData.setRemain(node);
        RequestTask task4 = new RequestTask(requestData, function);

        task1.setNext(task2);
        task2.setNext(task3);
        task3.setNext(task4);
        sendRequest(task1);
    }


    @Override
    public void valveOnOffControl(List<Node> valve, boolean ifLock, Integer opening, TaskFunction function) {
        if (!online()) {
            function.doApply(CommStatus.OffLine, valve);
            return;
        }
        for (Node node : valve) {
            ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
            RccTaskFunction.SyncFunction syncFunction = new RccTaskFunction.SyncFunction(function.getPriority());
            if (ifLock && opening == 100) {
                requestData.valveCtrl(node.getSerial(), 0x55);
                requestData.setRemain(node);
                sendRequest(requestData, function);
            } else if (ifLock && opening == 0) {
                requestData.valveCtrl(node.getSerial(), 0x99);
                requestData.setRemain(node);
                sendRequest(requestData, function);
            } else if (!ifLock && opening == 100) {
                requestData.valveCtrl(node.getSerial(), 0x66);
                requestData.setRemain(node);
                sendRequest(requestData, function);
            } else if (!ifLock && opening == 0) {
                requestData.valveCtrl(node.getSerial(), 0x77);
                requestData.setRemain(node);
                sendRequest(requestData, function);
            } else if (ifLock) {
//                requestData.valveOnOffControl(node.getSerial(), opening);
//                requestData.setRemain(node);
//                sendRequest(requestData, function);
//
//                requestData = new ApportionCollectorRequestData(serial());
//                requestData.valveCtrl(node.getSerial(), 0x11);
//                sendRequest(requestData, syncFunction);

                RequestTask task1 = new RequestTask(getRequest(node, 0xff), new ApportionFunction(this, function.getPriority(), "切换自由模式"));
                RequestTask task2 = new RequestTask(getRequest(node, 0x11), new ApportionFunction(this, function.getPriority(), "锁定开度"));
                requestData.valveOnOffControl(node.getSerial(), opening);
                requestData.setRemain(node);
                RequestTask task3 = new RequestTask(requestData, function);

                task1.setNext(task2);
                task2.setNext(task3);
                sendRequest(task1);

            } else {
                requestData.valveCtrl(node.getSerial(), 0xff);
                sendRequest(requestData, syncFunction);

                requestData = new ApportionCollectorRequestData(serial());
                requestData.valveOnOffControl(node.getSerial(), opening);
                requestData.setRemain(node);
                sendRequest(requestData, function);
            }
        }
    }

    public void valveTemperatureLock(List<Node> valves, boolean ifLock, float temperature, TaskFunction function) {
        if (!online()) {
            function.doApply(CommStatus.OffLine, valves);
            return;
        }
        ApportionCollectorRequestData requestData = new ApportionCollectorRequestData(serial());
        RccTaskFunction.SyncFunction syncFunction = new RccTaskFunction.SyncFunction(function, timeout(), function.getPriority());
        for (Node node : valves) {
            requestData.enterDebugMode(node.getSerial());
            sendRequest(requestData, syncFunction);
            Boolean chooseRes = syncFunction.waitResult();
            if (chooseRes != null && chooseRes) {
                requestData.setDebugModeAngleAdjustment(node.getSerial());
                sendRequest(requestData, syncFunction);
                chooseRes = syncFunction.waitResult();
                if (chooseRes != null && chooseRes) {
                    requestData.setDebuggingModeSetTheTemperature(node.getSerial(), temperature);
                    requestData.setRemain(node);
                    sendRequest(requestData, function);
                }
            }
        }
    }

    @Override
    public void receive(ConcentratorResponseData data) {
        if (data instanceof RunaConcenResponseData) {
            RunaConcenResponseData responseData = (RunaConcenResponseData) data;
            for (Object o : responseData.getData()) {
                if (o instanceof HotMeterVO) {
                    HotMeterVO hotMeterVO = (HotMeterVO) o;
                    String meterSerial = hotMeterVO.getMeterSerial();
                    if (null != meterSerial && meterSerial.length() < 14) {
                        CommMeter commMeter = RepositoryServicePersis.getByNetSerialAndSerialLeftLike(serial(), meterSerial);
                        if (null != commMeter) {
                            hotMeterVO.setMeterSerial(commMeter.getSerial());
                        }
                    }
                }
            }
        }
        super.receive(data);
    }

    @Override
    public void readNodeRecord(List<Integer> indexes, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitRecord(List<Node> valveSerial, Integer model, Map param, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitModel(List<Node> valveSerial, boolean model, TaskFunction function) {

    }

    @Override
    public void sentExtendParam(ExtendParam param, TaskFunction function) {

    }

    @Override
    public void readPublicUnitRecord(Node valveSerial, Integer model, TaskFunction function) {

    }

    @Override
    public void readPublicUnitAndMeter(Node valveSerial, Node meterSerial, TaskFunction function) {

    }

}
